// RTSP Server

#include "xop/RtspServer.h"
#include "net/Timer.h"
#include "net/SocketUtil.h"
#include <thread>
#include <memory>
#include <iostream>
#include <string>

class TSFile
{
public:
	TSFile(int buf_size=499892);
	~TSFile();

	bool Open(const char *path);
	void Close();

	bool IsOpened() const
	{ return (m_file != NULL); }

	int ReadFrame(char* in_buf, int in_buf_size, bool* end);
    
private:
	FILE *m_file = NULL;
	char *m_buf = NULL;
	int  m_buf_size = 0;
	int  m_bytes_used = 0;
	int  m_count = 0;
};

void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, TSFile* ts_file);

int main(int argc, char **argv)
{	
	if(argc != 2) {
		printf("Usage: %s test.ts  \n", argv[0]);
		return 0;
	}

	TSFile ts_file;
	if(!ts_file.Open(argv[1])) {
		printf("Open %s failed.\n", argv[1]);
		return 0;
	}

	std::string suffix = "live";
	std::string ip     = xop::SocketUtil::GetLocalIp();
	std::string port = "8554";
	std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;
	
	std::shared_ptr<xop::EventLoop> event_loop(new xop::EventLoop());
	std::shared_ptr<xop::RtspServer> server = xop::RtspServer::Create(event_loop.get());

	if (!server->Start("0.0.0.0", atoi(port.c_str()))) {
		printf("RTSP Server listen on %s failed.\n", port.c_str());
		return 0;
	}

#ifdef AUTH_CONFIG
	server->SetAuthConfig("-_-", "admin", "12345");
#endif

	xop::MediaSession *session = xop::MediaSession::CreateNew("live"); 
	session->AddSource(xop::channel_0, xop::TSSource::CreateNew()); 
	//session->StartMulticast(); 
	session->SetNotifyCallback([] (xop::MediaSessionId session_id, uint32_t clients){
		std::cout << "The number of rtsp clients: " << clients << std::endl;
	});
   
	xop::MediaSessionId session_id = server->AddSession(session);
         
	std::thread t1(SendFrameThread, server.get(), session_id, &ts_file);
	t1.detach(); 

	std::cout << "Play URL: " << rtsp_url << std::endl;

	while (1) {
		xop::Timer::Sleep(100);
	}

	getchar();
	return 0;
}

void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, TSFile* ts_file)
{       
	int buf_size = 1999944;
	std::unique_ptr<uint8_t> frame_buf(new uint8_t[buf_size]);

	while(1) {
		bool end_of_frame = false;
		int frame_size = ts_file->ReadFrame((char*)frame_buf.get(), buf_size, &end_of_frame);
		if(frame_size > 0) {
			xop::AVFrame videoFrame = {0};
			videoFrame.type = 0; 
			videoFrame.size = frame_size;
			videoFrame.timestamp = xop::TSSource::GetTimestamp();
			videoFrame.buffer.reset(new uint8_t[videoFrame.size]);    
			memcpy(videoFrame.buffer.get(), frame_buf.get(), videoFrame.size);
			rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame);
		}
		else {
			break;
		}
      
		xop::Timer::Sleep(40); 
	};
}

TSFile::TSFile(int buf_size)
    : m_buf_size(buf_size)
{
	m_buf = new char[m_buf_size];
}

TSFile::~TSFile()
{
	delete m_buf;
}

bool TSFile::Open(const char *path)
{
	m_file = fopen(path, "rb");
	if(m_file == NULL) {      
		return false;
	}

	return true;
}

void TSFile::Close()
{
	if(m_file) {
		fclose(m_file);
		m_file = NULL;
		m_count = 0;
		m_bytes_used = 0;
	}
}

int TSFile::ReadFrame(char* in_buf, int in_buf_size, bool* end)
{
	if(m_file == NULL) {
		return -1;
	}

	int bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
	if(bytes_read == 0) {
		fseek(m_file, 0, SEEK_SET); 
		m_count = 0;
		m_bytes_used = 0;
		bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
		if(bytes_read == 0)         {            
			this->Close();
			return -1;
		}
	}

	int size = (bytes_read<=in_buf_size ? bytes_read : in_buf_size);
	memcpy(in_buf, m_buf, size); 

	m_count += 1;
	m_bytes_used += size;
	fseek(m_file, m_bytes_used, SEEK_SET);
	return size;
}


